package br.unicamp.ic.mc747;

import interfacesFerrovia.TratadorDeEventos;

import java.util.List;

import malhaFerroviaria.Ferrovia;

/**
 * Classe que implementa a interface Tratador de Eventos, esta eh a classe que seja instanciada
 * na Ferrovia
 * 
 * @author Guilherme Martinez Sampaio
 */
public class TratadorDeEventosImplement implements TratadorDeEventos {

	private Integer instanteAtual = 0;
	
	private Monitor monitor;
	
	private Ferrovia ferrovia;
	
	public TratadorDeEventosImplement() {
		ferrovia = Ferrovia.getInstance();
		monitor = new Monitor(ferrovia);
		setInstanteAtual(new Integer(0));
	}
	
	@Override
	public void alarmeChave(String idChave, int instanteAtual,
			TipoFalha tipoDeFalha) {
		System.out.println("==> alarmeChave id:"+idChave+" t:"+instanteAtual+" falha:"+tipoDeFalha);

	}

	@Override
	public void alarmeComposicao(String idComposicao, int instanteAtual,
			TipoFalha tipoDeFalha) {
		System.out.println("==> alarmeComposicao id:"+idComposicao+" t:"+instanteAtual+" falha:"+tipoDeFalha);

	}

	@Override
	public void chegadaComposicao(String idComposicao, int instanteAtual,
			String idTrecho) {
		System.out.println("==> Chegada de Composicao id:"+idComposicao+" t:"+instanteAtual+" trecho:"+idTrecho);

	}

	@Override
	public void entradaComposicaoChave(String idChave, int instanteAtual,
			String idComposicao, String idTrechoOrigem) {
		System.out.println("==> entrada na chave id:"+idChave+" t:"+instanteAtual+
				           " id.Comp.:"+idComposicao+" tr.Origem:"+idTrechoOrigem);
		
	}

	@Override
	public void partidaComposicao(String idComposicao, int instanteAtual,
			String idTrecho) {
		System.out.println("==> partida composicao id:"+idComposicao+" t:"+instanteAtual+" trecho:"+idTrecho);
		Composicao c = monitor.getComposicaoPorId(idComposicao);
		//for(String str: c.getItinerario())
//			System.err.print(str+" ");
//		System.out.println();

		String[] outraComposicao = monitor.composicaoDisputaItinerario(idComposicao);
		if(outraComposicao != null)// && outraComposicao[0] != null && outraComposicao[1] != null)
			monitor.defineItinerarioPrioritario(idComposicao, outraComposicao[0], outraComposicao[1], getInstanteAtual());
		
		// checa se existe possibilidade de batida
		if(monitor.composicaoDisputaChave(idComposicao)){
			//desacelera composicao para evitar acidente
			if (monitor.getComposicaoPorId(idComposicao).getVelocidadeAtual() > 5) {
				monitor.ferrovia.frearComposicao(idComposicao, 5, false);
			}
			monitor.agendaTrocaDeEstadoDaProximaChave(idComposicao);
		// garante estado da proxima chave
		} else {
			monitor.garanteEstadoDaProximaChave(idComposicao);
		}
	}

	@Override
	public void passagemComposicao(String idTrecho, int instanteAtual,
			float posicao, String idComposicao, float velocidade,
			boolean sentidoAB) {
		System.out.println("==> passagem composicao id:"+idComposicao+" t:"+instanteAtual+ " trecho:"+idTrecho+" pos:"+posicao+
							" vel:"+velocidade+ " sent.AB:"+sentidoAB);
		
		try {
						
			//checa se precisa manobrar chave
			// monitor.manobraChave(idComposicao, instanteAtual);
			
			//checa se comeca a desacelerar
			/*
			if(monitor.deveDesacelerarParaEstacionar(idComposicao, instanteAtual)){
				//freia composicao
				float frenagemIdeal = monitor.desaceleracaoIdeal(idComposicao, instanteAtual);
				if (monitor.getComposicaoPorId(idComposicao).getVelocidadeAtual() > 0.001f) {
					monitor.ferrovia.frearComposicao(idComposicao, 0.001f, frenagemIdeal);
				}
			}
			*/
			// checa se existem composicoes no mesmo trecho em sentidos contrarios
			monitor.verificaColisaoFrontalComposicao(idComposicao);
			
		} catch (SecurityException e) {
			e.printStackTrace();
		}
	}

	@Override
	public void saidaComposicaoChave(String idChave, int instanteAtual,
			String idComposicao, String idTrechoDestino) {
		System.out.println("==> saida da chave id:"+idChave+" t:"+instanteAtual+" id.Comp:"+
				           idComposicao+" tr.Dest:"+idTrechoDestino);
		
		String[] outraComposicao = monitor.composicaoDisputaItinerario(idComposicao);
		if(outraComposicao != null)
			monitor.defineItinerarioPrioritario(idComposicao, outraComposicao[0], outraComposicao[1], getInstanteAtual());
		
//		// se existe disputa por essa chave
//		if(monitor.existeDisputaPorChave(idChave, idComposicao)){
//			//avisa proxima composicao para acelerar
//			monitor.aceleraComposicaoConflitante(idChave);
//		}
		
		// checa se existe possibilidade de batida
		if(monitor.composicaoDisputaChave(idComposicao)){
			//desacelera composicao para evitar acidente
			if (monitor.getComposicaoPorId(idComposicao).getVelocidadeAtual() > 5) {
				monitor.ferrovia.frearComposicao(idComposicao, 5, false);
			}
			monitor.agendaTrocaDeEstadoDaProximaChave(idComposicao);
		// garante estado da proxima chave
		} else {
			monitor.garanteEstadoDaProximaChave(idComposicao);
		}
		
		monitor.atualizaChave(idChave);
		monitor.liberaChave(idComposicao, idChave);
	}

	@Override
	public void tic(int instanteAtual) {
		this.setInstanteAtual(instanteAtual);

		List<Composicao> composicoes = monitor.getComposicoesAEstacionar();

		for (Composicao c : composicoes) {
			if (c.getPosicaoAtual() <= monitor.ferrovia.consultaDistMinParada(c.getId())) {
				monitor.ferrovia.frearComposicao(c.getId(), 0.0001f, c.getFrenagemMaxima());
			}
		}
		
		// teste
//		Chave ch = monitor.getChavePorId("x1");
//		System.out.println("Chave [id:"+ch.getId()+", conc:"+ch.getTempoConclusao()+
//				", emMudanca:"+ch.getEmMudanca());
		
		//		System.out.println("instanteAtual = "+instanteAtual);
		// nada a fazer, neste caso
	}

	public void setInstanteAtual(Integer instanteAtual) {
		this.instanteAtual = instanteAtual;
	}

	public Integer getInstanteAtual() {
		return instanteAtual;
	}


	
	
}
